import json
import uuid
import time
import requests
from typing import Dict, Optional, Any
from urllib.parse import urlparse
from .uu_md5_util import UUMD5Util
from .request_encryptor import RequestEncryptor
from .response_decryptor import ResponseDecryptor
from .rsa_util import RSAUtil
from .db.cons_manager import ConsManager
from tenacity import retry, stop_after_attempt, wait_fixed, retry_if_exception_type, retry_if_exception
import requests
from .utils.logger import get_logger, MODULE_MAIN

# 新增：用于检测5xx响应，触发自动重试
def _is_retryable_http_error(e):
    # 仅对requests.Response对象的5xx响应重试
    resp = getattr(e, 'response', None)
    if resp and 500 <= resp.status_code < 600:
        return True
    return False

class RequestInterceptor:
    def __init__(self):
        self.session = requests.Session()
        self.logger = get_logger(MODULE_MAIN)

    @retry(
        stop=stop_after_attempt(3),
        wait=wait_fixed(2),
        retry=(
            retry_if_exception_type((requests.Timeout, requests.ConnectionError)) |
            retry_if_exception(_is_retryable_http_error)
        )
    )
    def _robust_request(self, method, url, send_data, req_headers, timeout, data, **kwargs):
        method = method.upper()
        if method == "POST":
            resp = self.session.post(url, data=send_data, headers=req_headers, timeout=timeout, **kwargs)
        elif method == "GET":
            resp = self.session.get(url, params=data, headers=req_headers, timeout=timeout, **kwargs)
        elif method == "PUT":
            resp = self.session.put(url, data=send_data, headers=req_headers, timeout=timeout, **kwargs)
        elif method == "DELETE":
            resp = self.session.delete(url, headers=req_headers, timeout=timeout, **kwargs)
        else:
            raise ValueError(f"不支持的请求方法: {method}")
        # 5xx自动重试：抛出异常让tenacity捕获
        if 500 <= resp.status_code < 600:
            err = requests.HTTPError(f"服务器异常: {resp.status_code}")
            err.response = resp
            raise err
        return resp

    def post(self, url: str, data: Optional[Any] = None, json: Optional[Dict] = None,
             headers: Optional[Dict[str, str]] = None, **kwargs) -> requests.Response:
        """发送POST请求
        
        Args:
            url: 请求URL
            data: 表单数据
            json: JSON数据
            headers: 请求头
            **kwargs: 其他关键字参数
            
        Returns:
            requests.Response: 响应对象
        """
        return self.session.post(url, data=data, json=json, headers=headers, **kwargs)

    @staticmethod
    def encrypt_request_data(data: dict) -> (str, str):
        """
        加密请求数据，自动使用系统公钥，返回加密后的数据和加密后的sk
        """
        import uuid
        import json
        from .rsa_util import RSAUtil
        from .request_encryptor import RequestEncryptor
        sk = str(uuid.uuid4()).replace('-', '')
        public_key = RSAUtil.get_public_key()
        encrypted_sk = RSAUtil.encrypt(sk, public_key)
        encryptor = RequestEncryptor()
        encrypted_data = encryptor.encrypt(json.dumps(data, ensure_ascii=False), sk)
        return encrypted_data, encrypted_sk

    @staticmethod
    def decrypt_response_data(response_text: str, sk_header: str) -> str:
        """
        解密响应数据，自动使用系统私钥，返回明文字符串
        """
        from .rsa_util import RSAUtil
        from .response_decryptor import ResponseDecryptor
        private_key = RSAUtil.get_private_key()
        return ResponseDecryptor.decrypt_response(response_text, sk_header)

    def send_request(self, url: str, method: str = "POST", data: Optional[dict] = None, headers: Optional[dict] = None,
                     need_encrypt: bool = False,
                     timeout: int = 120,
                     **kwargs) -> dict:
        """
        统一处理加密请求和解密响应的接口（自动用系统公钥/私钥）
        Args:
            url: 请求URL
            method: 请求方法（POST/GET/PUT/DELETE）
            data: 请求数据（dict）
            headers: 请求头（dict）
            need_encrypt: 是否需要加密（加密时自动解密响应）
            timeout: 超时时间（秒）
            **kwargs: 其它requests参数
        Returns:
            dict: 结构化响应
        """
        import json
        # self.logger.info(f"请求准备: url={url}, method={method}, need_encrypt={need_encrypt}, timeout={timeout}")
        if headers is None:
            headers = {}
        req_headers = headers.copy()

        send_data = data
        if need_encrypt:
            try:
                encrypted_data, encrypted_sk = self.encrypt_request_data(data)
                send_data = encrypted_data
                req_headers["sk"] = encrypted_sk
                req_headers["content-type"] = "application/json; charset=utf-8"
                # self.logger.debug(f"请求体已加密, sk头已添加")
            except Exception as e:
                self.logger.error(f"加密请求体失败: {e}")
                return {"code": 500, "message": f"加密请求体失败: {e}", "raw_content": None}
        else:
            if data is not None:
                send_data = json.dumps(data, ensure_ascii=False)
                req_headers["content-type"] = "application/json; charset=utf-8"

        try:
            response = self._robust_request(method, url, send_data, req_headers, timeout, data, **kwargs)
            resp_headers = dict(response.headers)
            resp_preview = response.text[:500] if hasattr(response, 'text') else str(response)
            print("\n===== 响应头 =====")
            for k, v in resp_headers.items():
                print(f"{k}: {v}")
            print("===== 响应内容预览 =====")
            print(resp_preview)
            print("====================\n")
            # self.logger.info(f"请求已发送: {url} [{method}] 响应码: {getattr(response, 'status_code', None)} 响应头: {resp_headers} 响应内容预览: {resp_preview}")
        except requests.Timeout:
            self.logger.warning(f"请求超时: {url}")
            return {
                "code": 408,
                "message": "请求超时，请检查网络或稍后重试。",
                "raw_content": None
            }
        except requests.ConnectionError:
            self.logger.warning(f"网络连接异常: {url}")
            return {
                "code": 503,
                "message": "网络连接异常，请检查网络。",
                "raw_content": None
            }
        except requests.HTTPError as e:
            resp = getattr(e, 'response', None)
            if resp is not None and 500 <= resp.status_code < 600:
                self.logger.error(f"服务器5xx错误: {resp.status_code}, url={url}")
                return {
                    "code": resp.status_code,
                    "message": f"服务器错误({resp.status_code})，请稍后重试。",
                    "raw_content": resp.text
                }
            else:
                self.logger.error(f"HTTP异常: {e}")
                return {
                    "code": resp.status_code if resp else 500,
                    "message": f"HTTP异常: {e}",
                    "raw_content": resp.text if resp else None
                }
        except Exception as e:
            self.logger.error(f"请求异常: {url}, 错误: {e}")
            return {
                "code": 500,
                "message": f"请求异常: {e}",
                "raw_content": None
            }

        try:
            # 405安全拦截检测
            if response.status_code == 405 and "很抱歉，由于您访问的URL有可能对网站造成安全威胁" in response.text:
                self.logger.error(f"405安全拦截: {url}")
                return {
                    "code": 405,
                    "message": "很抱歉，由于您访问的URL有可能对网站造成安全威胁，您的访问被阻断。请尝试重新登录，如果重新登录后问题依旧，请尝试换个网络",
                    "raw_content": response.text
                }
            content_type = response.headers.get("content-type", "").lower()
            content = response.text
            # content-type兼容处理
            if need_encrypt:
                sk_header = response.headers.get("sk")
                if not sk_header:
                    self.logger.warning(f"响应缺少sk头，直接返回明文内容")
                    # 按content-type处理
                    if "application/json" in content_type:
                        resp_data = json.loads(content)
                    elif "text/" in content_type:
                        resp_data = {"code": response.status_code, "message": "文本响应", "raw_content": content}
                    else:
                        resp_data = {"code": response.status_code, "message": "未知响应类型", "raw_content": content}
                    # 常见HTTP状态码结构化处理
                    if response.status_code == 401:
                        resp_data = {"code": 401, "message": "未授权或登录失效", "raw_content": content}
                    elif response.status_code == 403:
                        resp_data = {"code": 403, "message": "禁止访问", "raw_content": content}
                    elif response.status_code == 404:
                        resp_data = {"code": 404, "message": "资源未找到", "raw_content": content}
                    elif 400 <= response.status_code < 500:
                        resp_data = {"code": response.status_code, "message": f"客户端错误({response.status_code})", "raw_content": content}
                    elif 500 <= response.status_code < 600:
                        resp_data = {"code": response.status_code, "message": f"服务器错误({response.status_code})", "raw_content": content}
                    return resp_data
                try:
                    content = self.decrypt_response_data(content, sk_header)
                    self.logger.debug(f"响应体已解密")
                    # 解密后优先尝试json
                    try:
                        resp_data = json.loads(content)
                    except Exception:
                        resp_data = {"code": response.status_code, "message": "解密后非JSON响应", "raw_content": content}
                except Exception as e:
                    self.logger.error(f"解密响应体失败: {e}")
                    return {"code": 500, "message": f"解密响应体失败: {e}", "raw_content": content}
            else:
                if "application/json" in content_type:
                    resp_data = json.loads(content)
                elif "text/" in content_type:
                    resp_data = {"code": response.status_code, "message": "文本响应", "raw_content": content}
                else:
                    resp_data = {"code": response.status_code, "message": "未知响应类型", "raw_content": content}
            # 常见HTTP状态码结构化处理（无论是否加密）
            if response.status_code == 401:
                resp_data = {"code": 401, "message": "未授权或登录失效", "raw_content": content}
            elif response.status_code == 403:
                resp_data = {"code": 403, "message": "禁止访问", "raw_content": content}
            elif response.status_code == 404:
                resp_data = {"code": 404, "message": "资源未找到", "raw_content": content}
            elif 400 <= response.status_code < 500:
                resp_data = {"code": response.status_code, "message": f"客户端错误({response.status_code})", "raw_content": content}
            elif 500 <= response.status_code < 600:
                resp_data = {"code": response.status_code, "message": f"服务器错误({response.status_code})", "raw_content": content}
            return resp_data
        except Exception as e:
            self.logger.error(f"响应解析失败: {e}")
            return {
                "code": response.status_code if 'response' in locals() else 500,
                "message": f"HTTP错误或内容解析失败: {e}",
                "raw_content": response.text if 'response' in locals() else None
            }